package server;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;

public class ServerListener extends Thread {

	// 备用变量
	private String toAddress; // 备用存储寄信地址
	private String tmpAddress; // 用于存储地址以在用户下线时删除用户
	private String tmpMessage; // 备用存储消息

	private Socket sock; // 当前的线程中的客户

	private ArrayList<Socket> userList; // 拥有userList以在用户退出时找到该用户并删除
	private ArrayList<ServerSender> senderList; // 拥有sender列表以查找到要传输信息的对象调用其方法进行发送

	
	// 构造函数：传入sock、senderList
	public ServerListener(Socket sock, ArrayList<ServerSender> s, ArrayList<Socket> userList) {

		this.sock = sock;
		this.senderList = s;
		this.userList = userList;
		
	}

	
	// 从userList中找到指定的toAddres
	private Socket findUser(String toAddress) throws Exception {
		// 在userList中找指定user
		for (var user : this.userList) {
			if (toAddress.equals(user.getInetAddress().toString()))
				return user;
		}
		throw new Exception("no such user!");
	}

	// 读取文件 传入BufferedRewder，返回String
	private String read(BufferedReader reader) throws IOException {

		// 直接读取全部信息
		char[] tmp = new char[1024];
		reader.read(tmp);
		int length = 0; // 存储字符长度
		for (int i = 0; i < 1024; i++) {
			if (tmp[i] == 0) {
				length = i;
				break;
			}
		}
		return new String(tmp).substring(0, length);

	}

	// 传入地址，找到该Sender并发送消息
	private void sendMessage(String toAddress, String message) {
		for (var sender : this.senderList) {
			String address = sender.getSock().getInetAddress().toString();
			if (address.equals(toAddress)) // 找到了要发送给的用户的Sender
				sender.sendMessage(message); // 直接向该Sender传输要发送的对象
		}
	}
	
	// 找到地址传输文件
	private void sendFile(String toAddress,byte[] p,long length) throws InterruptedException {
		// 先发消息确定接下来要传文件
		String myAddress = sock.getInetAddress().toString();
		sendMessage(toAddress, "e"+myAddress+String.valueOf(length)); // 指令、发文件人、大小
		Thread.sleep(100);
		for (var sender : this.senderList) {
			String address = sender.getSock().getInetAddress().toString();
			if(address.equals(toAddress)) {
				// 调用sender的传输文件方法
				sender.sendFile(myAddress, p);
			}
		}
	}

	
	// 监听信息：收到信息进行处理
	public void run() {
		try (InputStream input = this.sock.getInputStream()) {
			System.out.println("监听就绪");
			
			tmpAddress = sock.getInetAddress().toString(); // 保留自己的地址，用于删除用户
			BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
			// 循环监听
			while (true) {
				
				Thread.sleep(100); // 收取消息延迟
				String tmpString = read(reader); // 获取信息

				System.out.println("收到"+ sock.getInetAddress().toString() +"的信息："+tmpString);
				switch (tmpString.charAt(0)) {

				// 发回发信人
				case 'a':
					// 解析
					toAddress = tmpAddress; // 原路返回
					this.tmpMessage = "a"+"You say:"+tmpString.substring(1);
					sendMessage(toAddress, tmpMessage);
					break;

				// 群聊
				case 'b':
					// 发送给除自己的在线的所有人
					for (var user : userList) {
						// 如果是自己的话就不再发送
//						if(toAddress.equals(sock.getInetAddress().toString()))
//							continue;
						toAddress = user.getInetAddress().toString();
						tmpMessage = "b" + tmpAddress + tmpString.substring(1); // 添加发出人
						sendMessage(toAddress, tmpMessage);
					}
					break;

				// 私聊 信息里带有地址
				case 'c':
					// 获取地址
					int length = InetAddress.getLocalHost().toString().length(); // 获取地址长度
					toAddress = tmpString.substring(1, length + 1); // 获取地址
					tmpMessage = "c" + tmpAddress + tmpString.substring(length + 1); // 修改地址
					sendMessage(toAddress, tmpMessage);
					break;

				// 文件接受
				case 'e':
					System.out.println("收到文件，准备传输");
					int length1 = InetAddress.getLocalHost().toString().length();
					toAddress = tmpString.substring(1); // 获取文件传输地址
					long length2 = Long.parseLong(tmpString.substring(length1+1)); // 获取文件大小
					// 紧接着读取传过来的文件
					FileInputStream inputStream = (FileInputStream) input; // 获取
					byte[] p =new byte[1024];
					int n;
					
					// 目前只支持小于1024字节的文件 大于的话一次传输不完
					while((length2 -= 1024) > 0) {
						inputStream.read(p); // 把文件读到p里
						sendFile(toAddress,p,length2); // 传输文件p、地址
					}
					
				default:
					break;
				}
			}

		} catch (Exception e) {
			// TODO Auto-generated catch block
			try {
				sock.close();
			} catch (Exception e1) {
				// TODO: handle exception
			}
			// 把断开连接的用户从userList删去
			System.out.println("用户" + tmpAddress.toString() + "下线");
			try {
				userList.remove(findUser(tmpAddress.toString()));
			} catch (Exception e2) {
				// TODO Auto-generated catch block
				System.out.println("删去用户出现问题!");
				e2.printStackTrace();
			}
			System.out.println("已删去该用户");
		}
	}


}
